From 07d39299ead9d936c05242d2aab664b7112c3070 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Dec 2016 05:49:57 +0100 Subject: [PATCH] gsk: Replace gsk_render_node_set_opacity() ... with gsk_opacity_node_new(). Also implement support for opacity in gtk_widget_snapshot() using this new node. --- docs/reference/gsk/gsk4-sections.txt | 3 +- gsk/gskenums.h | 4 +- gsk/gskglrenderer.c | 7 +- gsk/gskrendernode.c | 40 -------- gsk/gskrendernode.h | 6 +- gsk/gskrendernodeimpl.c | 127 +++++++++++++++++++++++++ gsk/gskrendernodeprivate.h | 2 +- gsk/gskvulkanrenderpass.c | 8 -- gtk/gtkwidget.c | 55 +++++++---- gtk/inspector/gtktreemodelrendernode.c | 4 + gtk/inspector/recorder.c | 7 -- 11 files changed, 179 insertions(+), 84 deletions(-) diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index 6126c4f4fe..486e31d9d0 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -29,7 +29,6 @@ gsk_render_node_unref GskRenderNodeType gsk_render_node_get_node_type gsk_render_node_draw -gsk_render_node_set_opacity GskBlendMode gsk_render_node_set_blend_mode GskScalingFilter @@ -44,6 +43,8 @@ gsk_container_node_get_n_children gsk_container_node_get_child gsk_transform_node_new gsk_transform_node_get_child +gsk_opacity_node_new +gsk_opacity_node_get_child GSK_IS_RENDER_NODE GSK_RENDER_NODE diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 579e3d9c50..caba77f6ab 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -31,6 +31,7 @@ * @GSK_TEXTURE_NODE: A node drawing a #GskTexture * @GSK_TRANSFORM_NODE: A node that renders its child after applying a * matrix transform + * @GSK_OPACITY_NODE: A node that changes the opacity of its child * * The type of a node determines what the node is rendering. * @@ -42,7 +43,8 @@ typedef enum { GSK_CAIRO_NODE, GSK_COLOR_NODE, GSK_TEXTURE_NODE, - GSK_TRANSFORM_NODE + GSK_TRANSFORM_NODE, + GSK_OPACITY_NODE } GskRenderNodeType; /** diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c index bb98e2ff42..7812121131 100644 --- a/gsk/gskglrenderer.c +++ b/gsk/gskglrenderer.c @@ -592,11 +592,6 @@ project_item (const graphene_matrix_t *projection, static gboolean render_node_needs_render_target (GskRenderNode *node) { - double opacity = gsk_render_node_get_opacity (node); - - if (opacity < 1.0) - return TRUE; - return FALSE; } @@ -647,7 +642,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, graphene_matrix_multiply (modelview, &self->mvp, &item.mvp); item.z = project_item (projection, modelview); - item.opacity = gsk_render_node_get_opacity (node); + item.opacity = 1.0; item.blend_mode = gsk_render_node_get_blend_mode (node); diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 1a343ae852..ab41235c4d 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -97,8 +97,6 @@ gsk_render_node_new (const GskRenderNodeClass *node_class) self->ref_count = 1; - self->opacity = 1.0; - self->min_filter = GSK_SCALING_FILTER_NEAREST; self->mag_filter = GSK_SCALING_FILTER_NEAREST; @@ -185,44 +183,6 @@ gsk_render_node_get_bounds (GskRenderNode *node, node->node_class->get_bounds (node, bounds); } -/** - * gsk_render_node_set_opacity: - * @node: a #GskRenderNode - * @opacity: the opacity of the node, between 0 (fully transparent) and - * 1 (fully opaque) - * - * Sets the opacity of the @node. - * - * Since: 3.90 - */ -void -gsk_render_node_set_opacity (GskRenderNode *node, - double opacity) -{ - g_return_if_fail (GSK_IS_RENDER_NODE (node)); - g_return_if_fail (node->is_mutable); - - node->opacity = CLAMP (opacity, 0.0, 1.0); -} - -/** - * gsk_render_node_get_opacity: - * @node: a #GskRenderNode - * - * Retrieves the opacity set using gsk_render_node_set_opacity(). - * - * Returns: the opacity of the #GskRenderNode - * - * Since: 3.90 - */ -double -gsk_render_node_get_opacity (GskRenderNode *node) -{ - g_return_val_if_fail (GSK_IS_RENDER_NODE (node), 0.0); - - return node->opacity; -} - void gsk_render_node_set_scaling_filters (GskRenderNode *node, GskScalingFilter min_filter, diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 2119dfb760..3be25035b1 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -74,8 +74,10 @@ GDK_AVAILABLE_IN_3_90 GskRenderNode * gsk_transform_node_get_child (GskRenderNode *node); GDK_AVAILABLE_IN_3_90 -void gsk_render_node_set_opacity (GskRenderNode *node, - double opacity); +GskRenderNode * gsk_opacity_node_new (GskRenderNode *child, + double opacity); +GDK_AVAILABLE_IN_3_90 +GskRenderNode * gsk_opacity_node_get_child (GskRenderNode *node); GDK_AVAILABLE_IN_3_90 void gsk_render_node_set_blend_mode (GskRenderNode *node, diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index feb7f0891c..764b702df8 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -692,3 +692,130 @@ gsk_transform_node_get_transform (GskRenderNode *node, graphene_matrix_init_from_matrix (transform, &self->transform); } +/*** GSK_OPACITY_NODE ***/ + +typedef struct _GskOpacityNode GskOpacityNode; + +struct _GskOpacityNode +{ + GskRenderNode render_node; + + GskRenderNode *child; + double opacity; +}; + +static void +gsk_opacity_node_finalize (GskRenderNode *node) +{ + GskOpacityNode *self = (GskOpacityNode *) node; + + gsk_render_node_unref (self->child); +} + +static void +gsk_opacity_node_make_immutable (GskRenderNode *node) +{ + GskOpacityNode *self = (GskOpacityNode *) node; + + gsk_render_node_make_immutable (self->child); +} + +static void +gsk_opacity_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskOpacityNode *self = (GskOpacityNode *) node; + graphene_rect_t bounds; + + cairo_save (cr); + + /* clip so the push_group() creates a smaller surface */ + gsk_render_node_get_bounds (self->child, &bounds); + cairo_rectangle (cr, bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height); + cairo_clip (cr); + + cairo_push_group (cr); + + gsk_render_node_draw (self->child, cr); + + cairo_pop_group_to_source (cr); + cairo_paint_with_alpha (cr, self->opacity); + + cairo_restore (cr); +} + +static void +gsk_opacity_node_get_bounds (GskRenderNode *node, + graphene_rect_t *bounds) +{ + GskOpacityNode *self = (GskOpacityNode *) node; + + gsk_render_node_get_bounds (self->child, bounds); +} + +static const GskRenderNodeClass GSK_OPACITY_NODE_CLASS = { + GSK_OPACITY_NODE, + sizeof (GskOpacityNode), + "GskOpacityNode", + gsk_opacity_node_finalize, + gsk_opacity_node_make_immutable, + gsk_opacity_node_draw, + gsk_opacity_node_get_bounds +}; + +/** + * gsk_opacity_node_new: + * @child: The node to draw + * @opacity: The opacity to apply + * + * Creates a #GskRenderNode that will drawn the @child with reduced + * @opacity. + * + * Returns: A new #GskRenderNode + * + * Since: 3.90 + */ +GskRenderNode * +gsk_opacity_node_new (GskRenderNode *child, + double opacity) +{ + GskOpacityNode *self; + + g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL); + + self = (GskOpacityNode *) gsk_render_node_new (&GSK_OPACITY_NODE_CLASS); + + self->child = gsk_render_node_ref (child); + self->opacity = CLAMP (opacity, 0.0, 1.0); + + return &self->render_node; +} + +/** + * gsk_opacity_node_get_child: + * @node: a opacity @GskRenderNode + * + * Gets the child node that is getting opacityed by the given @node. + * + * Returns: (transfer none): The child that is getting opacityed + **/ +GskRenderNode * +gsk_opacity_node_get_child (GskRenderNode *node) +{ + GskOpacityNode *self = (GskOpacityNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_OPACITY_NODE), NULL); + + return self->child; +} + +double +gsk_opacity_node_get_opacity (GskRenderNode *node) +{ + GskOpacityNode *self = (GskOpacityNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_OPACITY_NODE), 1.0); + + return self->opacity; +} + diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index c4e3c48751..3ad5c43658 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -52,7 +52,7 @@ void gsk_render_node_make_immutable (GskRenderNode *node); void gsk_render_node_get_bounds (GskRenderNode *node, graphene_rect_t *frame); -double gsk_render_node_get_opacity (GskRenderNode *node); +double gsk_opacity_node_get_opacity (GskRenderNode *node); cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node); diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c index 86ac1a198b..9b28951a23 100644 --- a/gsk/gskvulkanrenderpass.c +++ b/gsk/gskvulkanrenderpass.c @@ -66,9 +66,6 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, .node = node }; - if (gsk_render_node_get_opacity (node) < 1.0) - goto fallback; - switch (gsk_render_node_get_node_type (node)) { case GSK_NOT_A_RENDER_NODE: @@ -115,11 +112,6 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, break; } - - return; - -fallback: - g_array_append_val (self->render_ops, op); } void diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index cf2b96156e..85783162bb 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -6298,15 +6298,8 @@ gtk_widget_draw_internal (GtkWidget *widget, GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (widget); GdkWindow *event_window = NULL; gboolean result; - gboolean push_group; RenderMode mode; - push_group = - widget->priv->alpha != 255 && !_gtk_widget_is_toplevel (widget); - - if (push_group) - cairo_push_group (cr); - #ifdef G_ENABLE_CONSISTENCY_CHECKS if (_gtk_widget_get_alloc_needed (widget)) g_warning ("%s %p is drawn without a current allocation. This should not happen.", G_OBJECT_TYPE_NAME (widget), widget); @@ -6343,6 +6336,12 @@ gtk_widget_draw_internal (GtkWidget *widget, } else { + gboolean push_group = + widget->priv->alpha != 255 && !_gtk_widget_is_toplevel (widget); + + if (push_group) + cairo_push_group (cr); + if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE)) { g_signal_emit (widget, widget_signals[DRAW], @@ -6355,6 +6354,13 @@ gtk_widget_draw_internal (GtkWidget *widget, GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr); cairo_restore (cr); } + + if (push_group) + { + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0); + } } #ifdef G_ENABLE_DEBUG @@ -6390,13 +6396,6 @@ gtk_widget_draw_internal (GtkWidget *widget, } #endif - if (push_group) - { - cairo_pop_group_to_source (cr); - cairo_set_operator (cr, CAIRO_OPERATOR_OVER); - cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0); - } - if (cairo_status (cr) && event_window != NULL) { @@ -15538,6 +15537,7 @@ gtk_widget_snapshot (GtkWidget *widget, GtkAllocation clip; GtkAllocation alloc; RenderMode mode; + double opacity; if (_gtk_widget_get_alloc_needed (widget)) return; @@ -15548,6 +15548,13 @@ gtk_widget_snapshot (GtkWidget *widget, if (gtk_snapshot_clips_rect (snapshot, &bounds)) return; + if (_gtk_widget_is_toplevel (widget)) + opacity = 1.0; + else + opacity = widget->priv->alpha / 255.0; + if (opacity <= 0.0) + return; + /* Compatibility mode: if the widget does not have a render node, we draw * using gtk_widget_draw() on a temporary node */ @@ -15565,6 +15572,11 @@ gtk_widget_snapshot (GtkWidget *widget, } else { + if (opacity < 1.0) + gtk_snapshot_push (snapshot, TRUE, "OpacityGroup<%s>", G_OBJECT_TYPE_NAME (widget)); + + klass->snapshot (widget, snapshot); + if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE)) { /* Compatibility mode: if there's a ::draw signal handler, we add a @@ -15573,17 +15585,24 @@ gtk_widget_snapshot (GtkWidget *widget, gboolean result; cairo_t *cr; - klass->snapshot (widget, snapshot); - cr = gtk_snapshot_append_cairo_node (snapshot, &bounds, "DrawSignalContents<%s>", G_OBJECT_TYPE_NAME (widget)); g_signal_emit (widget, widget_signals[DRAW], 0, cr, &result); cairo_destroy (cr); } - else + + if (opacity < 1.0) { - klass->snapshot (widget, snapshot); + GskRenderNode *opacity_node, *node; + + node = gtk_snapshot_pop (snapshot); + opacity_node = gsk_opacity_node_new (node, opacity); + gsk_render_node_set_name (opacity_node, "Opacity"); + gsk_render_node_unref (node); + + gtk_snapshot_append_node (snapshot, opacity_node); + gsk_render_node_unref (opacity_node); } } } diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c index 617b4b7f78..b25ae64633 100644 --- a/gtk/inspector/gtktreemodelrendernode.c +++ b/gtk/inspector/gtktreemodelrendernode.c @@ -530,6 +530,10 @@ append_node (GtkTreeModelRenderNode *nodemodel, append_node (nodemodel, gsk_transform_node_get_child (node), priv->nodes->len - 1); break; + case GSK_OPACITY_NODE: + append_node (nodemodel, gsk_opacity_node_get_child (node), priv->nodes->len - 1); + break; + case GSK_CONTAINER_NODE: { gint elt_index; diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c index 659921c242..bffab8393a 100644 --- a/gtk/inspector/recorder.c +++ b/gtk/inspector/recorder.c @@ -152,13 +152,6 @@ populate_render_node_properties (GtkListStore *store, -1); g_free (tmp); - tmp = g_strdup_printf ("%.2f", gsk_render_node_get_opacity (node)); - gtk_list_store_insert_with_values (store, NULL, -1, - 0, "Opacity", - 1, tmp, - -1); - g_free (tmp); - gtk_list_store_insert_with_values (store, NULL, -1, 0, "Has Surface", 1, gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE ? "TRUE" : "FALSE", -- 2.30.2